package cn.zfs.springcloud.datasource.aspect;

import cn.zfs.springcloud.datasource.annotation.DataSourceAndTransaction;
import cn.zfs.springcloud.datasource.annotation.ManagementTransaction;
import cn.zfs.springcloud.datasource.contextholder.DataSourceContextHolder;
import cn.zfs.springcloud.datasource.init.InitData;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 切换数据源 开启事务 切面
 */
@SuppressWarnings({"Duplicates", "SpringAutowiredFieldsWarningInspection"})
@Aspect
@Component
@Order(2)
public class DataSourceAndTransactionAspect {

    private Logger logger = LoggerFactory.getLogger(SwitchDataSourceAspect.class);

    @Autowired
    private AspectPublic aspectPublic;
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private InitData initData;


    @Pointcut("@annotation(cn.zfs.springcloud.datasource.annotation.DataSourceAndTransaction)")
    private void dataSourceAndTransactionAspectPointcut() {
    }

    @Before("dataSourceAndTransactionAspectPointcut()")
    public void before(JoinPoint point) {
        Class<?> clazz = point.getTarget().getClass(); //获得当前访问的class
        String methodName = point.getSignature().getName(); //获得当前访问的方法名
        Class[] argClass = ((MethodSignature) point.getSignature()).getParameterTypes();//获得当前方法的参数的类型
        try {
            Method method = clazz.getMethod(methodName, argClass); //获得当前访问的方法对象
            logger.debug("判断是否存在@DataSourceAndTransaction");
            if (method.isAnnotationPresent(DataSourceAndTransaction.class)) {
                DataSourceAndTransaction dataSourceAndTransaction = method.getAnnotation(DataSourceAndTransaction.class);
                aspectPublic.switchDataSource(dataSourceAndTransaction.dataSourceName(), initData.getDefaultDataSourceName());
                aspectPublic.openTransaction(applicationContext, DataSourceContextHolder.getDetermineCurrentLookupKey(),
                        dataSourceAndTransaction.openTransaction(), dataSourceAndTransaction.openTransactionNum(),
                        dataSourceAndTransaction.thisMethodOpenTransaction());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @AfterReturning("dataSourceAndTransactionAspectPointcut()")
    public void after() {
        aspectPublic.commitTransactionClearThreadLocal();
        aspectPublic.clearThreadLocal();
    }

    @AfterThrowing(pointcut = "dataSourceAndTransactionAspectPointcut()", throwing = "throwable")
    public void afterThrowing(Throwable throwable) throws Throwable {
        logger.error("出现异常", throwable);
        aspectPublic.rollbackTransaction();
        aspectPublic.clearThreadLocal();
        throw throwable;
    }
}
